/**
 * Copyright (c) 2011 eelpo.com
 * All rights reserved.
 */
package com.eelpo.cmmp.core.spring.orm.jpa;

import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceException;
import javax.persistence.Query;

import com.eelpo.common.query.criteria.Criteria;

import org.springframework.dao.DataAccessException;
import org.springframework.orm.jpa.JpaCallback;
import org.springframework.orm.jpa.JpaOperations;
import org.springframework.orm.jpa.support.JpaDaoSupport;

/**
 * <pre>
 * 
 * 数据访问基础公共类,代理JpaTemplate的操作方法
 * 
 * </pre>
 * 
 * @author <a href="mailto:Brian@eelpo.com">汪洪州</a>
 * @since 1.0
 */

public class BasicCommonDao extends JpaDaoSupport implements JpaOperations {

	@Resource(name = "entityManagerFactory")
	public void injectEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
		super.setEntityManagerFactory(entityManagerFactory);
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.springframework.orm.jpa.JpaOperations#execute(org.springframework
	 * .orm.jpa.JpaCallback)
	 */
	@Override
	public <T> T execute(JpaCallback<T> action) throws DataAccessException {
		return getJpaTemplate().execute(action);
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.springframework.orm.jpa.JpaOperations#executeFind(org.springframework
	 * .orm.jpa.JpaCallback)
	 */
	@Override
	public List<?> executeFind(JpaCallback<?> action) throws DataAccessException {
		return getJpaTemplate().executeFind(action);
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see org.springframework.orm.jpa.JpaOperations#find(java.lang.Class,
	 * java.lang.Object)
	 */
	@Override
	public <T> T find(Class<T> entityClass, Object id) throws DataAccessException {
		return getJpaTemplate().find(entityClass, id);
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.springframework.orm.jpa.JpaOperations#getReference(java.lang.Class,
	 * java.lang.Object)
	 */
	@Override
	public <T> T getReference(Class<T> entityClass, Object id) throws DataAccessException {
		return getJpaTemplate().getReference(entityClass, id);
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see org.springframework.orm.jpa.JpaOperations#contains(java.lang.Object)
	 */
	@Override
	public boolean contains(Object entity) throws DataAccessException {
		return getJpaTemplate().contains(entity);
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see org.springframework.orm.jpa.JpaOperations#refresh(java.lang.Object)
	 */
	@Override
	public void refresh(Object entity) throws DataAccessException {
		getJpaTemplate().refresh(entity);
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see org.springframework.orm.jpa.JpaOperations#persist(java.lang.Object)
	 */
	@Override
	public void persist(Object entity) throws DataAccessException {
		getJpaTemplate().persist(entity);
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see org.springframework.orm.jpa.JpaOperations#merge(java.lang.Object)
	 */
	@Override
	public <T> T merge(T entity) throws DataAccessException {
		return getJpaTemplate().merge(entity);
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see org.springframework.orm.jpa.JpaOperations#remove(java.lang.Object)
	 */
	@Override
	public void remove(Object entity) throws DataAccessException {
		getJpaTemplate().remove(entity);
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see org.springframework.orm.jpa.JpaOperations#flush()
	 */
	@Override
	public void flush() throws DataAccessException {
		getJpaTemplate().flush();
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see org.springframework.orm.jpa.JpaOperations#find(java.lang.String)
	 */
	@Override
	public List<?> find(String queryString) throws DataAccessException {
		return getJpaTemplate().find(queryString);
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see org.springframework.orm.jpa.JpaOperations#find(java.lang.String,
	 * java.lang.Object[])
	 */
	@Override
	public List<?> find(String queryString, Object... values) throws DataAccessException {
		return getJpaTemplate().find(queryString, values);
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.springframework.orm.jpa.JpaOperations#findByNamedParams(java.lang
	 * .String, java.util.Map)
	 */
	@Override
	public List<?> findByNamedParams(String queryString, Map<String, ?> params) throws DataAccessException {
		return getJpaTemplate().findByNamedParams(queryString, params);
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.springframework.orm.jpa.JpaOperations#findByNamedQuery(java.lang.
	 * String)
	 */
	@Override
	public List<?> findByNamedQuery(String queryName) throws DataAccessException {
		return getJpaTemplate().findByNamedQuery(queryName);
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.springframework.orm.jpa.JpaOperations#findByNamedQuery(java.lang.
	 * String, java.lang.Object[])
	 */
	@Override
	public List<?> findByNamedQuery(String queryName, Object... values) throws DataAccessException {
		return getJpaTemplate().findByNamedQuery(queryName, values);
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.springframework.orm.jpa.JpaOperations#findByNamedQueryAndNamedParams
	 * (java.lang.String, java.util.Map)
	 */
	@Override
	public List<?> findByNamedQueryAndNamedParams(String queryName, Map<String, ?> params) throws DataAccessException {
		return getJpaTemplate().findByNamedQueryAndNamedParams(queryName, params);
	}

	/**
	 * 查询所有实体
	 * 
	 * @param entity
	 *            要查询的实体
	 * @return 返回实体列表
	 * @throws DataAccessException
	 *             抛出数据访问异常
	 */
	public List<?> getAll(Class<?> entityClass) throws DataAccessException {
		return find("FROM ".concat(entityClass.getSimpleName()));
	}

	/**
	 * 查询所有实体的数量
	 * 
	 * @param entityClass
	 *            要查询的实体
	 * @return 返回所有实体的数量
	 * @throws DataAccessException
	 *             抛出数据访问异常
	 */
	public int getAllCount(final Class<?> entityClass) throws DataAccessException {
		return execute(new JpaCallback<Integer>() {
			@Override
			public Integer doInJpa(EntityManager entitymanager) throws PersistenceException {

				Query query = entitymanager.createQuery("SELECT COUNT(*) FROM ".concat(entityClass.getSimpleName()));

				return Integer.valueOf(query.getSingleResult().toString());
			}
		});
	}

	/**
	 * 根据Criteria辅助类，查询实体列表
	 * 
	 * @param criteria
	 *            查询辅助类
	 * @return 返回列表数据
	 * @throws DataAccessException
	 *             抛出数据访问异常
	 */
	@SuppressWarnings("unchecked")
	public <T> List<T> getResultList(final Criteria criteria) throws DataAccessException {
		return (List<T>) executeFind(new JpaCallback<List<T>>() {

			@Override
			public List<T> doInJpa(EntityManager em) throws PersistenceException {

				Query query = em.createQuery(criteria.getJpql());
				Object[] objs = criteria.getParameters().toArray();
				for (int i = 1; i <= objs.length; i++) {
					query.setParameter(i, objs[i - 1]);
				}

				if (criteria.isPaging()) {
					query.setFirstResult(criteria.getFirstResult());
					query.setMaxResults(criteria.getMaxResults());
				}

				if (!criteria.getHints().isEmpty()) {
					Map<String, Object> hints = criteria.getHints();
					for (String key : hints.keySet()) {
						query.setHint(key, hints.get(key));
					}
				}

				return query.getResultList();
			}
		});
	}

	/**
	 * 根据Criteria辅助类，查询单个实例
	 * 
	 * @param criteria
	 *            查询辅助类
	 * @return 返回列表数据
	 * @throws DataAccessException
	 *             抛出数据访问异常
	 */
	@SuppressWarnings("unchecked")
	public <T> T getSingleResult(final Criteria criteria) throws DataAccessException {
		return (T) execute(new JpaCallback<T>() {

			@Override
			public T doInJpa(EntityManager em) throws PersistenceException {

				Query query = em.createQuery(criteria.getJpql());
				Object[] objs = criteria.getParameters().toArray();
				for (int i = 1; i <= objs.length; i++) {
					query.setParameter(i, objs[i - 1]);
				}

				if (!criteria.getHints().isEmpty()) {
					Map<String, Object> hints = criteria.getHints();
					for (String key : hints.keySet()) {
						query.setHint(key, hints.get(key));
					}
				}

				return (T) query.getSingleResult();
			}
		});
	}

	/**
	 * 根据QueryHelper辅助类查询实体的数量
	 * 
	 * @param criteria
	 *            查询辅助类
	 * @return 返回实体的数量
	 * @throws DataAccessException
	 *             抛出数据访问异常
	 */
	public int getResultCount(final Criteria criteria) throws DataAccessException {

		return execute(new JpaCallback<Integer>() {

			@Override
			public Integer doInJpa(EntityManager em) throws PersistenceException {
				Query query = em.createQuery(criteria.getJpql());
				Object[] objs = criteria.getParameters().toArray();
				for (int i = 1; i <= objs.length; i++) {
					query.setParameter(i, objs[i - 1]);
				}
				return Integer.valueOf(query.getSingleResult().toString());
			}
		});
	}
}
